package com.heatingcharge.security.config;

import com.heatingcharge.security.JwtUserDetailsServiceImpl;
import com.heatingcharge.security.filter.JwtAuthenticationTokenFilter;
import com.heatingcharge.security.handle.AuthenticationEntryPointImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsUtils;

/**
 * Created with IntelliJ IDEA.
 * Description: Security配置类
 * User: Devin
 * Date: 2019-07-04
 * Time: 16:11
 */
@Slf4j
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private AuthenticationEntryPointImpl authenticationEntryPoint;
    @Autowired
    private AccessDeniedHandler accessDeniedHandler;
    @Autowired
    private JwtAuthenticationTokenFilter authenticationTokenFilter;
    @Autowired
    private JwtUserDetailsServiceImpl userDetailsService;

    /**
     * 解决 无法直接注入 AuthenticationManager
     *
     * @return
     * @throws Exception
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.csrf().disable()// 由于使用的是JWT，我们这里不需要csrf
                .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint).and()//认证失败处理类
                .exceptionHandling().accessDeniedHandler(accessDeniedHandler).and()//权限不足处理类
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()// 基于token，所以不需要session
                .authorizeRequests()// 过滤请求
                // 所有 / 的所有请求 都放行
                .requestMatchers(CorsUtils::isPreFlightRequest).permitAll()    //新增 对preflight放行
                .antMatchers("/login", "/favicon.ico").permitAll()// 对于登录login 图标 要允许匿名访问
                .antMatchers(
                        HttpMethod.GET,
                        "/*.html",
                        "/**/*.html",
                        "/**/*.css",
                        "/**/*.js"
                ).permitAll()
                .antMatchers("/aliPay/*").permitAll()
                .antMatchers("/wxPay/*").permitAll()
                .antMatchers("/clearOff/*").permitAll()
                // swagger start
                .antMatchers("/swagger-ui.html").anonymous()
                .antMatchers("/swagger-resources/**").anonymous()
                .antMatchers("/webjars/**").anonymous()
                .antMatchers("/*/api-docs").anonymous()
                // swagger end
                .antMatchers("/captcha.jpg")//验证码
                .permitAll()
                .anyRequest().authenticated()
                .and()
                .headers().frameOptions().disable();
        // 添加JWT filter
        httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//        auth.userDetailsService(userDetailsService)// 设置UserDetailsService
//                .passwordEncoder(passwordEncoder());// 使用BCrypt进行密码的hash
        auth.authenticationProvider(authenticationProvider());
    }
    /**
     * 装载BCrypt密码编码器 密码加密
     *
     * @return
     */
    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        //抛出异常UserNameNotFoundException
        provider.setHideUserNotFoundExceptions(false);
        provider.setUserDetailsService(userDetailsService);// 设置UserDetailsService
        provider.setPasswordEncoder(passwordEncoder());// 使用BCrypt进行密码的hash
        return provider;
    }
}
